 /**
  * ### 滚动条插件
  * @module scroll
  * @requires ui
  * @requires drag
  * @requires base
  */
define("scroll", ["ui", "drag", "base"], function(ui, drag, base, Lyx){
	
	/**
	 * @constructor
	 * @alias module:scroll
	 * @param {element} el 目标元素 
	 * @param {object} [config] 配置属性
	 * @param {string} [config.scroll = "y"] 鼠标滚动时，移动哪个轴
	 * @param {number | string} [config.barWidth] 滚动条宽度，未设置xBarWidth或yBarWidth时使用该值
	 * @param {object} [config.bar] 滚动条样式，在未配置xBar或yBar时使用该值
	 * @param {object} [config.barBack] 滚动条背景样式，在未配置xBarBack或yBarBack时使用该值
	 * @param {number} [config.speed] 滚动速度，在未配置xSpeed或ySpeed时使用该值
	 * @param {boolean} [config.mouseover] 滚动条是否根据鼠标移入移出改变状态
	 * @param {number | string} [config.xBarWidth] x轴滚动条宽度
	 * @param {number | string} [config.yBarWidth] y轴滚动条宽度
	 * @param {object} [config.xBarBack] x轴滚动条背景样式
	 * @param {object} [config.yBarBack] y轴滚动条背景样式
	 * @param {object} [config.xBar] x轴滚动条样式
	 * @param {object} [config.yBar] y轴滚动条样式
	 * @param {number} [config.xSpeed] x轴滚动速度
	 * @param {number} [config.ySpeed] y轴滚动速度
	 * @param {boolean} [config.xMouseover] 鼠标移出时是否隐藏x轴滚动条
	 * @param {boolean} [config.yMouseover] 鼠标移出时是否隐藏y轴滚动条
	 */
	
	return Lyx.createClass(function(p2t){
		/**
		 * 初始化滚动插件
		 * @memberof module:scroll.prototype
		 */
		p2t.init = function(el, config)
		{
			if(Lyx.type(el) === "string")
			{
				el = ui.$(el);
			}

			// 读取配置
			config = config || {};

			/**
			 * x轴滚动条位置
			 * @member {number}
			 */
			this.x = 0;

			/**
			 * x轴滚动条位置
			 * @member {number}
			 */
			this.y = 0;

			/**
			 * 滚动窗口宽度
			 * @member {number}
			 * @default 窗口设置的宽度
			 */
			this.width = 0;

			/**
			 * 滚动窗口高度
			 * @member {number}
			 * @default 窗口设置的高度
			 */
			this.height = 0;

			/**
			 * x轴可滚动区域大小
			 * @member {number}
			 */
			this.scrollX = 0;

			/**
			 * y轴可滚动区域大小
			 * @member {number}
			 */
			this.scrollY = 0;

			/**
			 * x轴滚动条宽度
			 * @member {number}
			 * @default config中设置或者为2
			 */
			this.xBarWidth = config.xbarWidth || config.barWidth || 2;

			/**
			 * y轴滚动条宽度
			 * @member {number}
			 * @default config中设置或者为2
			 */
			this.yBarWidth = config.ybarWidth || config.barWidth || 2;

			/**
			 * x轴滚动条是否开启
			 * @member {boolean}
			 */
			this.xBarSwitch = undefined;

			/**
			 * x轴滚动条是否开启
			 * @member {boolean}
			 */
			this.yBarSwitch = undefined;

			/**
			 * 鼠标移入显示滚动条，移出隐藏滚动条
			 * @member {boolean}
			 * @default false
			 */
			this.mouseover = false;

			/**
			 * 滚动体是否支持拖动
			 * @member {boolean}
			 * @default true
			 */
			this.dragSwitch = true;

			this.$x = {
				set: function(value)
				{
					// 位置最小为0，最大为可滚动区域值
					var x = base.scope(0, this.scrollX, value);

					// 设置x轴滚动位置
					this.window.transform = "translate(" + -x + "px," + -this.y + "px)";

					// 设置x轴滚动条位置
					this.xBar.left = x / this.scrollX * (this.width - this.xBar.width);

					Lyx.lock["left"] = x != 0;
					Lyx.lock["right"] = x != this.scrollX;

					return x;
				}
			}
			this.$y = {
				set: function(value)
				{
					// 位置最小为0，最大为可滚动区域值
					var y = base.scope(0, this.scrollY, value);

					// 设置y轴滚动位置
					this.window.transform = "translate(" + -this.x + "px," + -y + "px)";

					// 设置y轴滚动条位置
					this.yBar.top = y / this.scrollY * (this.height - this.yBar.height);

					Lyx.lock["top"] = y != 0;
					Lyx.lock["bottom"] = y != this.scrollY;

					return y;
				}
			}
			this.$width = {
				set: function(value)
				{
					// 设置滚动窗口宽度
					this.style.width = value;

					// 设置x轴滚动条背景宽度
					this.xBarBack.width = value;

					// 重新计算x轴滚动条宽度
					this.xBar.width = base.scope(5, value, 
						value * value / this.window.width);

					// y轴滚动条贴边
					this.yBarBack.left = value - this.yBarWidth;
				},
				get: function()
				{
					return this.style.width;
				}
			}
			this.$height = {
				set: function(value)
				{
					// 设置滚动窗口高度
					this.style.height = value;

					// 设置y轴滚动条背景高度
					this.yBarBack.height = value;

					// 重新计算y轴滚动条高度
					this.yBar.height = base.scope(5, value, 
						value * value / this.window.height);
					
					// x轴滚动条贴边
					this.xBarBack.top = value - this.xBarWidth;
				},
				get: function()
				{
					return this.style.height;
				}
			}
			this.$scrollX = {
				get: function()
				{
					// 可滚动区域大小
					var scroll = this.window.width - this.style.width;

					this.update("x");

					return scroll < 0 ? 0 : scroll;
				}
			}
			this.$scrollY = {
				get: function()
				{
					// 可滚动区域大小
					var scroll = this.window.height - this.style.height;

					this.update("y");

					return scroll < 0 ? 0 : scroll;
				}
			}

			this.$xBarWidth = {
				set: function(value)
				{
					// 修改x轴滚动条背景宽度
					this.xBarBack.width = value;

					// 修改y轴滚动条贴边
					this.xBarBack.top = this.height - value;
				}
			}
			this.$yBarWidth = {
				set: function(value)
				{
					// 修改y轴滚动条背景宽度
					this.yBarBack.width = value;

					// 修改y轴滚动条贴边
					this.yBarBack.left = this.width - value;
				}
			}
			this.$xBarSwitch = {
				set: function(value, oldValue)
				{
					// 防止重复操作
					if(value != oldValue)
					{
						if(this.xMouseover)
						{
							this.xMouseover = value;
						}
						this.xBarBack.display = value ? "" : "none";
					}
				}
			}
			this.$yBarSwitch = {
				set: function(value, oldValue)
				{
					// 防止重复操作
					if(value != oldValue)
					{
						if(this.yMouseover)
						{
							this.yMouseover = value;
						}
						this.yBarBack.display = value ? "" : "none";
					}
				}
			}
			this.$mouseover = {
				set: function(value, oldValue)
				{
					if(value != oldValue)
					{
						// 监听鼠标移入事件，显示滚动条
						ui.hander[value ? "add" : "remove"](el, "mouseover", this.onmouseover);

						// 监听鼠标移出事件，隐藏滚动条
						ui.hander[value ? "add" : "remove"](el, "mouseleave", this.onmouseout);
						
						this.xBarBack.opacity = 1;
						this.yBarBack.opacity = 1;

						// 如果开启移入显示的话，那滚动条应该打开，但是关闭的时候不影响滚动条开关
						this.yBarSwitch = value ? true : this.yBarSwitch;
						this.xBarSwitch = value ? true : this.xBarSwitch;
					}
				}
			}

			this.$dragSwitch = {
				set: function(value)
				{
					this.drag.switch = value;
				}
			}

			// 监听所有前缀为$的属性
			Lyx.observe(this);

			/** 目标对象 */
			this.el = el;
			ui.css(this.el, {
				height: config.height,
				width: config.width
			});

			/** 代理el的style */
			this.style = ui.getStyle(this.el);

			var position = this.style.position;
			if(position === "static" || position == "inherit")
			{
				this.style.position = "relative";
			}

			// 将滚动窗口的默认滚动条隐藏
			this.el.style.overflow = "hidden";

			// 如果滚动窗口第一个子结点不是div，那就包裹一层
			if(this.el.firstElementChild.nodeName !== "DIV")
			{
				var childNodes = [];
				while(this.el.hasChildNodes())
				{
					if(el.firstChild != null)
					{
						childNodes.push(this.el.firstChild);
						this.el.removeChild(el.firstChild);
					}
				}
				var div = ui.addNode(this.el, "div", "innerFirst");
				Lyx.each(childNodes, function(index, el){
					div.appendChild(el);
				});
			}

			this.box = this.el.firstElementChild;

			/** 代理滚动体的style */
			this.window = ui.getStyle(this.el.firstElementChild);
			this.window.transition  = "0.3s";
			this.window.float = "left";
			this.window.position = "relative";

			// x轴滚动条背景默认样式
			var xBarBackStyle = {
				position: "absolute",
				top: this.height - this.xBarWidth,
				height: this.xBarWidth,
				width: this.width,
				background: "rgba(0, 0, 0, 0.1)",
				transition: ".3s",
				zIndex: 9999
			};

			// x轴滚动条的默认样式
			var xBarStyle = {
				position: "relative",
				left: 0,
				width: base.scope(5, this.width, 
					this.width * this.width / this.window.width),
				height: this.xBarWidth,
				background: "rgba(0,0,0,0.3)",
				borderRadius: this.xBarWidth / 2,
				transition: ".2s ease-out"
			};

			// y轴滚动条背景默认样式
			var yBarBackStyle = {
				position: "absolute",
				left: this.width - this.yBarWidth,
				height: this.height,
				width: this.yBarWidth,
				background: "rgba(0,0,0,0.1)",
				transition: ".3s",
				zIndex: 9999
			};

			// y轴滚动条的默认样式
			var yBarStyle = {
				position: "relative",
				top: 0,
				height: base.scope(5, this.height, 
					this.height * this.height / this.window.height),
				backgroundColor: "rgba(0,0,0,0.3)",
				borderRadius: this.yBarWidth / 2,
				transition: ".2s ease-out"
			};

			// 为x轴滚动条背景添加配置的样式
			Lyx.extend(xBarBackStyle, config.xBarBack || config.barBack, true);

			// 为x轴滚动条添加配置的样式
			Lyx.extend(xBarStyle, config.xBar || config.bar, true);

			// 为y轴滚动条背景添加配置的样式
			Lyx.extend(yBarBackStyle, config.yBarBack || config.barBack, true);

			// 为y轴滚动条添加配置的样式
			Lyx.extend(yBarStyle, config.yBar || config.bar, true);

			// 添加x轴滚动条背景
			var xBarBack = ui.addNode(this.el, "div", "innerFirst", {
				style: xBarBackStyle
			});

			// 添加x轴滚动条
			var xBar = ui.addNode(xBarBack, "div", "innerFirst", {
				style: xBarStyle
			});

			// 添加y轴滚动条背景
			var yBarBack = ui.addNode(this.el, "div", "innerFirst", {
				style: yBarBackStyle
			});

			// 添加y轴滚动条
			var yBar = ui.addNode(yBarBack, "div", "innerFirst", {
				style: yBarStyle
			});

			/** 代理x轴滚动条背景的style */
			this.xBarBack = ui.getStyle(xBarBack);

			/** 代理x轴滚动条的style */
			this.xBar = ui.getStyle(xBar);

			/** 代理y轴滚动条背景的style */
			this.yBarBack = ui.getStyle(yBarBack);

			/** 代理y轴滚动条的style */
			this.yBar = ui.getStyle(yBar);

			/**
			 * x轴滚动速度
			 * @default config中配置的xSpeed，或者config中配置的speed，或者为60
			 */
			this.xSpeed = config.xSpeed || config.speed || 60;

			/**
			 * y轴滚动速度
			 * @default config中配置的xSpeed，或者config中配置的speed，或者为60
			 */
			this.ySpeed = config.ySpeed || config.speed || 60;

			/**
			 * 滚动条默认移入显示，移出消失
			 * @default config配置的mouseover，或者true
			 */
			this.mouseover = Lyx.defaultValue(config.mouseover, true);

			/**
			 * 设置鼠标滑入滑出x轴是否开启隐藏滚动条
			 * @default config配置中xMouseover，或者为true
			 */
			this.xMouseover = Lyx.defaultValue(config.xMouseover, true);

			/**
			 * 设置鼠标滑入滑出y轴是否开启隐藏滚动条
			 * @default config配置中xMouseover，或者为true
			 */
			this.yMouseover = Lyx.defaultValue(config.yMouseover, true);

			/**
			 * 设置x轴滚动条是否显示
			 * @default config配置中xBarSwitch，或者内容宽度是否大于窗口宽度
			 */
			this.xBarSwitch = Lyx.defaultValue(config.xBarSwitch, this.window.width > this.width);

			/**
			 * 设置y轴滚动条是否显示
			 * @default config配置中yBarSwitch，或者内容高度是否大于窗口高度
			 */
			this.yBarSwitch = Lyx.defaultValue(config.yBarSwitch, this.window.height > this.height);

			/** 鼠标移入显示滚动条 */
			this.onmouseover = function()
			{
				if(this.xMouseover)
				{
					if(this.xBarBack.opacity < 1)
					{
						this.xBarBack.opacity = 1;
					}
				}
				if(this.yMouseover)
				{
					if(this.yBarBack.opacity < 1)
					{
						this.yBarBack.opacity = 1;
					}
				}
			}.bind(this);

			/** 鼠标移出隐藏滚动条 */
			this.onmouseout = function()
			{
				if(this.xMouseover)
				{
					if(this.xBarBack.opacity > 0)
					{
						this.xBarBack.opacity = 0;
					}
				}
				if(this.yMouseover)
				{
					if(this.yBarBack.opacity > 0)
					{
						this.yBarBack.opacity = 0;
					}
				}
			}.bind(this);

			/**
			 * 鼠标滚动方向
			 * @default "y"，滚动y轴
			 */
			this.scroll = config.scroll || "y";

			/**
			 * 触顶事件
			 * @callback
			 */
			this.onTop = function(){};

			/**
			 * 触底事件
			 * @callback
			 */
			this.onBottom = function(){};

			/**
			 * 触左边界
			 * @callback
			 */
			this.onLeft = function(){};

			/**
			 * 触右边界
			 * @callback
			 */
			this.onRight = function(){};

			Lyx.lock(["top"], function(){
				this.onTop();
			}, this);
			
			Lyx.lock(["bottom"], function(){
				this.onBottom();
			}, this);

			Lyx.lock(["left"], function(){
				this.onLeft();
			}, this);
			
			Lyx.lock(["right"], function(){
				this.onRight();
			}, this);

			// 为x轴滚动条添加拖动事件
			drag(xBar, {
				down: function()
				{
					this.xBar.transition = "";
					this.window.transition = "";
				}.bind(this),
				move: function(bar)
				{
					this.x = bar.style.left / this.width * this.window.width;

					// 禁止竖直移动
					bar.style.top = bar.top;
				}.bind(this),
				up: function(){
					this.xBar.transition = ".3s";
					this.window.transition = ".3s";
				}.bind(this)
			});

			// 为y轴滚动条添加拖动事件
			drag(yBar, {
				down: function()
				{
					this.yBar.transition = "";
					this.window.transition = "";
				}.bind(this),
				move: function(bar)
				{
					this.y = bar.style.top / this.height * this.window.height;

					// 禁止水平移动
					bar.style.left = bar.left;
				}.bind(this),
				up: function(){
					this.yBar.transition = ".3s";
					this.window.transition = ".3s";
				}.bind(this)
			});

			// 为滚动体添加拖动事件
			this.drag = drag(this.box, {
				down: function(drag)
				{
					this.window.transition = "";
					drag.inner.x = this.x;
					drag.inner.y = this.y;
				},
				move: function(drag)
				{
					drag.style.top = drag.top;
					drag.style.left = drag.left;
					this.x = drag.inner.x - drag.offsetX;
					this.y = drag.inner.y - drag.offsetY;
				},
				up: function()
				{
					this.window.transition = ".3s";
				}
			}, this);

			this.dragSwitch = Lyx.defaultValue(config.dragSwitch, true);

			this.lock = true;

			// 监听滚动动画结束事件
			ui.hander.add(el, "transitionend", function(){
				// log("动画结束");
			}.bind(this));

			// 监听鼠标滚动
			ui.hander.add(el, "mousewheel", function(event){
				ui.stop(event);
				if(this.lock)
				{
					var direction = event.wheelDelta || -event.detail;
					this[this.scroll] += this[this.scroll + "Speed"] * (direction > 0 ? -1 : 1);
				}
			}.bind(this));
		}

		/**
		 * 定位至顶部
		 * @memberof module:scroll.prototype
		 */
		p2t.toTop = function()
		{
			this.y = 0;
		}

		/**
		 * 定位至底部
		 * @memberof module:scroll.prototype
		 */
		p2t.toBottom = function()
		{
			this.y = this.scrollY;
		}

		p2t.scroll

		/**
		 * 定位至最左
		 * @memberof module:scroll.prototype
		 */
		p2t.toLeft = function()
		{
			this.x = 0;
		}

		/**
		 * 定位至最右
		 * @memberof module:scroll.prototype
		 */
		p2t.toRight = function()
		{
			this.x = this.scrollX;
		}

		/**
		 * 下一屏，根据设置决定是x轴的下一屏还是y轴的下一屏
		 * @memberof module:scroll.prototype
		 */
		p2t.next = function()
		{
			this[this.scroll] += this[this.scroll == "y" ? "height" : "width"];
		}

		/**
		 * 上一屏，根据设置决定是x轴的上一屏还是y轴的上一屏
		 * @memberof module:scroll.prototype
		 */
		p2t.last = function()
		{
			this[this.scroll] -= this[this.scroll == "y" ? "height" : "width"];
		}

		/**
		 * 当视图数据发生变化时，主动更新变化
		 * @memberof module:scroll.prototype
		 */
		p2t.update = function(axis)
		{
			if(Lyx.isUndefined(axis))
			{
				axis = "y";
				this.update("x");
			}
			var side = axis == "x" ? "width" : "height";
			axis += "Bar";
			// 滚动条高度
			this[axis][side] = base.scope(5, this[side],
				this[side] * this[side] / this.window[side]);
			if(this[axis][side] == this[side])
			{
				this[axis].display = "none";
			}
			else
			{
				this[axis].display = "";
			}
		}

		/**
		 * 滚动至指定位置，根据设置决定滚动x轴还是y轴
		 * @memberof module:scroll.prototype
		 */
		p2t.toIndex = function(index)
		{
			this[this.scroll] = (index - 1) * this[this.scroll == "y" ? "height" : "width"];
		}
	});
});